/*
 * Copyright (c) 2009, Jan Stender, Bjoern Kolbeck, Mikael Hoegqvist,
 *                     Felix Hupfeld, Felix Langner, Zuse Institute Berlin
 * 
 * Licensed under the BSD License, see LICENSE file for details.
 * 
 */
package org.xtreemfs.babudb;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map.Entry;

import org.xtreemfs.babudb.index.ByteRangeComparator;

/**
 * <p>Interface for an instance of the BabuDB.</p>
 * 
 * 
 * @author bjko
 * @author flangner
 *
 */
public interface BabuDB {

    /**
     * Version (name)
     */
    public static final String BABUDB_VERSION = "0.1.0 RC";
    /**
     * Version of the DB on-disk format (to detect incompatibilities).
     */
    public static final int BABUDB_DB_FORMAT_VERSION = 1;

    /**
     * shuts down the database.
     * @attention: does not create a final checkpoint!
     */
    public void shutdown();

    /**
     * Inserts a single key value pair (synchronously)
     * @param database name of database
     * @param indexId index id (0..NumIndices-1)
     * @param key the key
     * @param value the value
     * @throws BabuDBException if the operation failed
     */
    public void syncSingleInsert(String database, int indexId, byte[] key,
            byte[] value) throws BabuDBException;

    /**
     * Inserts a group of key value pair (synchronously)
     * @param irg the insert record group to execute
     * @throws BabuDBException if the operation failed
     */
    public void syncInsert(BabuDBInsertGroup irg) throws BabuDBException;

    /**
     * lookup a single key (synchronously)
     * @param database name of database
     * @param indexId index id (0..NumIndices-1)
     * @param key the key to look up
     * @return a view buffer to the result or null if there is no such entry
     * @throws BabuDBException if the operation failed
     */
    public byte[] syncLookup(String database, int indexId, byte[] key)
            throws BabuDBException;

    /**
     * synchronous wrapper for asyncUserDefinedLookup
     * @param database
     * @param udl the method to be executed
     * @return the result generated by the user defined lookup method
     * @throws BabuDBException
     */
    public Object syncUserDefinedLookup(String database, UserDefinedLookup udl)
            throws BabuDBException;

    /**
     * executes a user defined lookup method
     * @param database name of database
     * @param indexId index id (0..NumIndices-1)
     * @param key the key to start the iterator at
     * @return an iterator to the database starting at the first matching key. Returns key/value pairs in ascending order.
     * @throws BabuDBException if the operation failed
     */
    public Iterator<Entry<byte[], byte[]>> syncPrefixLookup(String database,
            int indexId, byte[] key) throws BabuDBException;

    /**
     * Creates a database using the default comparator (bytewise/ASCII string comparator)
     * @param databaseName name of the database
     * @param numIndices number of indices in the database
     * @throws BabuDBException if the database directory cannot be created or the config cannot be saved
     */
    public void createDatabase(String databaseName, int numIndices)
            throws BabuDBException;

    /**
     * Creates a new database
     * @param databaseName name, must be unique
     * @param numIndices the number of indices (cannot be changed afterwards)
     * @param comparators an array of ByteRangeComparators for each index (use only one instance)
     * @throws BabuDBException if the database directory cannot be created or the config cannot be saved
     */
    public void createDatabase(String databaseName, int numIndices,
            ByteRangeComparator[] comparators) throws BabuDBException;

    /**
     * Deletes a database
     * @param databaseName name of database to delete
     * @param deleteFiles if true, all snapshots are deleted as well
     * @throws BabuDBException
     */
    public void deleteDatabase(String databaseName, boolean deleteFiles)
            throws BabuDBException;

    /**
     * Creates a copy of database sourceDB by taking a snapshot, materializing it
     * and loading it as destDB. This does not interrupt operations on sourceDB.
     * @param sourceDB the database to copy
     * @param destDB the new database's name
     * @param rangeStart
     * @param rangeEnd
     * @throws BabuDBException
     * @throws IOException
     */
    public void copyDatabase(String sourceDB, String destDB, byte[] rangeStart,
            byte[] rangeEnd) throws BabuDBException, IOException;

    /**
     * Creates a checkpoint of all databases. The in-memory data is merged with the on-disk data and
     * is written to a new snapshot file. Database logs are truncated. This operation is thread-safe.
     * @throws BabuDBException if the checkpoint was not successful
     * @throws InterruptedException
     */
    public void checkpoint() throws BabuDBException, InterruptedException;

    /**
     * Creates a snapshot of all indices in a single database. The snapshot is
     * not materialized (use writeSnapshot)
     * and will be removed upon next checkpointing or shutdown.
     * @param dbName
     * @throws BabuDBException if the checkpoint was not successful
     * @throws InterruptedException
     * @return an array with the snapshot ID for each index in the database
     */
    public int[] createSnapshot(String dbName) throws BabuDBException,
            InterruptedException;

    /**
     * Writes a snapshot to disk.
     * @param dbName the database name
     * @param snapIds the snapshot IDs obtained from createSnapshot
     * @param directory the directory in which the snapshots are written
     * @throws org.xtreemfs.babudb.BabuDBException if the snapshot cannot be written
     */
    public void writeSnapshot(String dbName, int[] snapIds, String directory)
            throws BabuDBException;

    /**
     * Insert an group of inserts asynchronously.
     * @param ig the group of inserts
     * @param listener a callback for the result
     * @param context optional context object which is passed to the listener
     * @throws BabuDBException
     */
    public void asyncInsert(BabuDBInsertGroup ig,
            BabuDBRequestListener listener, Object context)
            throws BabuDBException;

    /**
     * Executes a  user defined method in the database worker's thread.
     * This can be more efficient than executing multiple individual lookups
     * (only a single enqueue operations).
     * @param databaseName the database in which to execute the method
     * @param listener a result listener
     * @param udl the method to be executed
     * @param context arbitrary context which is passed to the listener
     * @throws org.xtreemfs.babudb.BabuDBException
     */
    public void asyncUserDefinedLookup(String databaseName,
            BabuDBRequestListener listener, UserDefinedLookup udl,
            Object context) throws BabuDBException;

    /**
     * Creates a new group of inserts.
     * @param databaseName the database to which the inserts are applied
     * @return a insert record group
     * @throws BabuDBException
     */
    public BabuDBInsertGroup createInsertGroup(String databaseName)
            throws BabuDBException;

    /**
     * Lookup a key=value asynchronously
     * @param databaseName database which is queried
     * @param indexId the lookup index
     * @param key the key to lookup
     * @param listener a callback for the result
     * @param context optional context object which is passed to the listener
     * @throws BabuDBException
     */
    public void asyncLookup(String databaseName, int indexId, byte[] key,
            BabuDBRequestListener listener, Object context)
            throws BabuDBException;

    /**
     * Asynchronously prefix lookup for a key.
     * @param databaseName database which is queried
     * @param indexId the lookup index
     * @param key the key to lookup
     * @param listener a callback for the result
     * @param context optional context object which is passed to the listener
     * @throws BabuDBException
     */
    public void asyncPrefixLookup(String databaseName, int indexId, byte[] key,
            BabuDBRequestListener listener, Object context)
            throws BabuDBException;

    /**
     * Looks up a key in the database. Similar to syncLookup but executes in the
     * context of the calling thread.
     * @attention direct... methods should not be mixed with the other sync/async... operations
     *            and developers must make sure that readers and writers are synchronized correctly!
     * @param databaseName
     * @param indexId
     * @param key
     * @return
     * @throws org.xtreemfs.babudb.BabuDBException
     */
    public byte[] directLookup(String databaseName, int indexId, byte[] key) throws BabuDBException;

    public Iterator<Entry<byte[], byte[]>> directPrefixLookup(String databaseName, int indexId, byte[] key) throws BabuDBException;

    public void directInsert(BabuDBInsertGroup ig) throws BabuDBException;

}